package com.xtc.netty.tomcat;

import com.xtc.netty.tomcat.http.MyRequest;
import com.xtc.netty.tomcat.http.MyResponse;
import com.xtc.netty.tomcat.http.MyServlet;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpRequest;
import io.netty.handler.codec.http.HttpRequestDecoder;
import io.netty.handler.codec.http.HttpResponseEncoder;

import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * @author Administrator
 */
public class MyTomcat {

    private int port = 9090;

    public MyTomcat(int port) {
        this.port = port;
    }

    private Map<String, MyServlet> servletMapping = new HashMap<>();

    public static final String PATH_SUFFIX = ".path";
    public static final String CLASS_SUFFIX = ".servletClass";

    private void init() {
        try {
            InputStream inputStream = MyTomcat.class.getClassLoader().getResourceAsStream("config/web.properties");
            Properties properties = new Properties();
            properties.load(inputStream);
            for (Map.Entry<Object, Object> prop : properties.entrySet()) {
                String servletPathKey = (String) prop.getKey();
                if (servletPathKey.endsWith(PATH_SUFFIX)) {
                    String servletClassPathKey = servletPathKey + CLASS_SUFFIX;
                    String servletPath = (String) prop.getValue();
                    String servletClassPath = (String) properties.get(servletClassPathKey);
                    MyServlet myServlet = (MyServlet) Class.forName(servletClassPath).newInstance();
                    servletMapping.put(servletPath, myServlet);
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void start() {
        this.init();

        EventLoopGroup bossGroup = new NioEventLoopGroup();
        EventLoopGroup workGroup = new NioEventLoopGroup();

        try {
            ServerBootstrap serverBootstrap = new ServerBootstrap();
            serverBootstrap.group(workGroup, workGroup)
                    .channel(NioServerSocketChannel.class)
                    .option(ChannelOption.SO_BACKLOG, 128)
                    .childHandler(new ChannelInitializer<SocketChannel>() {
                        @Override
                        protected void initChannel(SocketChannel channel) throws Exception {
                            channel.pipeline()
                                    .addLast(new HttpResponseEncoder())
                                    .addLast(new HttpRequestDecoder())
                                    .addLast(new MyHandler());
                        }
                    })
                    .childOption(ChannelOption.SO_KEEPALIVE, true);

            ChannelFuture channelFuture = serverBootstrap.bind(this.port).sync();
            System.out.println("Tomcat 已启动，监听端口：" + this.port);

            channelFuture.channel().closeFuture().sync();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private class MyHandler extends ChannelInboundHandlerAdapter {
        @Override
        public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
            if (msg instanceof HttpRequest) {
                HttpRequest request = (HttpRequest) msg;

                MyRequest myRequest = new MyRequest(ctx, request);
                MyResponse myResponse = new MyResponse(ctx, request);

                String url = myRequest.getUrl();

                if (servletMapping.containsKey(url)) {
                    servletMapping.get(url).service(myRequest, myResponse);
                } else {
                    ctx.write("404 not found");
                }
            }
        }

        @Override
        public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
            cause.printStackTrace();
            ctx.close();
        }
    }

    public static void main(String[] args) {
        MyTomcat myTomcat = new MyTomcat(9090);
        myTomcat.start();
    }
}
